home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / windows4 / pcproj.zip / PROJWIND.CLS < prev    next >
Text File  |  1990-01-15  |  30KB  |  1,060 lines

  1. /* Maintain a Project chart in a Window. The ProjWindow is
  2.    responsible for all drawing of the project. The window 
  3.    has full scrolling and supports a keyboard interface.
  4.    If topMethod or botMethod are set, then the corresponding
  5.    method will be executed for each activity while displaying
  6.    the project.
  7.  
  8.    ProjWindow descends from class Window and inherits all of
  9.    its instance variables and methods.
  10.  
  11.    All strings are defined as resources for easy translation.
  12. */!!
  13.  
  14. inherit(Window, #ProjWindow, #(project     /* the project */
  15. fileName    /* of the project */
  16. actions     /* menu actions table */
  17. dirty       /* true if not saved */
  18. view        /* normal or zoomed */
  19. boxHeight   /* based on scrnsize */
  20. boxWidth    /* adjustable for zoom */
  21. boxHSpace   /* adjustable */
  22. activWidth  /* adjustable */
  23. hScrollPos  /* horiz scroll posn */
  24. vScrollPos  /* vert scroll posn */
  25. maxVisCol   /* max visible col */
  26. maxVisRow   /* max visible row */
  27. methTable   /* table of methods */
  28. topMethod   /* offset into table */
  29. botMethod   /* offset into table */
  30. gw          /* a GanttWindow */
  31. /* these are new for dragging */
  32. dragDC      /* for drawing */
  33. anchorPt    /* starting point */
  34. oldPt       /* end point */
  35. ), 2, nil)!!
  36.  
  37. now(ProjWindowClass)!!
  38.  
  39. /* Return the name of this class's MS-Windows window class
  40.   either for registration or new window creation. */
  41. Def wndClass(self)
  42. { ^"ProjWindow"  }!!
  43.  
  44. /* Create a new window class Struct.
  45.    Change the cursor to a cross.  */
  46. Def newWClass(self, lpCl, lpIcon | wc)
  47. { wc := newWClass(self:WindowClass, lpCl, lpIcon);
  48.   putWord(wc, Call LoadCursor(0, IDC_CROSS), 14);
  49.   ^wc;
  50. } !!
  51.  
  52. now(ProjWindow)!!
  53.  
  54. /* Respond to menu choice to run a program. 
  55.    By default, run MSDOS executive shell.*/
  56. Def run(self | dlg, progName)
  57. {
  58.   dlg := new(InputDialog, "Run","Program name:","MSDOS.EXE");
  59.   if runModal(dlg, INPUT_BOX, self) == IDOK
  60.     progName:=getText(dlg);
  61.     if not(find(progName, ".", 0))
  62.       progName := progName + ".EXE";
  63.     endif;
  64.     exec(progName);
  65.   endif;
  66. }!!
  67.  
  68. /* Handles menu choice to set colors. Global variables
  69.    CritColor and SlackColor determine the application
  70.    colors. */
  71. Def toggleColor(self)
  72. {
  73.   if CritColor <> BLACK
  74.     unCheckMenuItem(self, PW_COLOR);
  75.     CritColor := BLACK;
  76.     SlackColor := BLACK;
  77.   else
  78.     checkMenuItem(self, PW_COLOR);
  79.     CritColor := RED;
  80.     SlackColor := BLUE;
  81.   endif;
  82.   invalidate(self);
  83.   if gw invalidate(gw); endif;
  84. }!!
  85.  
  86. /* Create a new Milestone */
  87. Def newMilestone(self)
  88. {
  89.   newActivity(self, Milestone);
  90. }!!
  91.  
  92. /* Create the window using a "main" window style. */
  93. Def create(self, par, wName, rect, style)
  94.   ^create(self:Window, nil, wName, rect, 
  95.      WS_OVERLAPPEDWINDOW bitOr WS_VSCROLL bitOr WS_HSCROLL);
  96. }!!
  97.  
  98. /* Set up a dummy project, menus and the method table. */
  99. Def init(self)
  100. {  
  101.   setProject(self, new(Project));
  102.   setAutoCalc(project, true);  
  103.   setView(self, #normal);
  104.   setScrollBars(self);
  105.   setMenus(self);
  106.   checkMenuItem(self, PW_AUTOCALC);
  107.   checkMenuItem(self, PW_COLOR);
  108.   setMethTable(self);
  109. }!!
  110.  
  111. /* Set the project. */
  112. Def setProject(self, aProject)
  113. {
  114.   project := aProject;
  115. }!!
  116.  
  117. /* Set the resolution for the size of nodes, spacing etc.
  118.    based on the font text size.  There are two views,
  119.    normal and small.  Both are based on text font size so
  120.    that they will display adequately with any resolution. */
  121. Def setView(self, aView | hDC, ts)
  122. {
  123.   view := aView;
  124.   hDC := getContext(self);    /* so we can get text size */
  125.   ts := textSize(self, hDC);  /* x is width, y is height */
  126.   releaseContext(self, hDC);
  127.   if view == #small
  128.     boxWidth := x(ts) * 4;
  129.     boxHSpace := x(ts)/2 + 1;
  130.     boxHeight := y(ts) + 4;
  131.   else
  132.     boxWidth := asInt(x(ts)*8);
  133.     boxHSpace := x(ts) + 2;
  134.     boxHeight := y(ts) * 2;   
  135.   endif;
  136.   activWidth := boxWidth + boxHSpace;
  137.   reSize(self, 0, 0L);        /* so scrolling is adjusted */
  138. }!!
  139.  
  140. /* Set the scroll bar ranges and initial positions. */
  141. Def setScrollBars(self)
  142.   Call SetScrollRange(hWnd, SB_HORZ, 0, PW_MAX_COLS, 0);
  143.   Call SetScrollRange(hWnd, SB_VERT, 0, PW_MAX_ROWS, 0);
  144.   hScrollPos := vScrollPos := 0; 
  145. }!!
  146.  
  147. /* Set up the method table used for display options. 
  148.    Each of these methods should be applicable to all
  149.    activities in the project, that is, both Milestones
  150.    and Tasks. */
  151. Def setMethTable(self)
  152. {
  153.     methTable := #(#getTime, 
  154.                    #getSlack, 
  155.                    #getCost,
  156.                    #getEarlyStart,
  157.                    #getEarlyFinish,
  158.                    #getLateStart,
  159.                    #getLateFinish);
  160.   topMethod := 3;
  161. }!!
  162.  
  163. /* Set the method to display info below each box. 
  164.    The offset refers to the position in the
  165.    methTable. */
  166. Def setBotMethod(self, offset)
  167. {
  168.   botMethod := offset;
  169. }!!
  170.  
  171. /* Set the method to display info atop each box. 
  172.    The offset refers to the position in the
  173.    methTable. */
  174. Def setTopMethod(self, offset)
  175. {
  176.   topMethod := offset;
  177. }!!
  178.  
  179. /* Add an about box and load menu resources.
  180.    Set up the menu actions table. Each entry
  181.    consists of a constant ID and a message
  182.    that will be performed. */
  183. Def setMenus(self)
  184. {
  185.   addAbout(self);
  186.   loadMenu(self, "PWMenus");
  187.   setMenu(self, hMenu);
  188.  
  189.   actions := new(Dictionary, 30);
  190.  
  191.   add(actions, PW_FILE_NEW, #fileNew);
  192.   add(actions, PW_FILE_OPEN, #fileOpenAs);
  193.   add(actions, PW_FILE_SAVE, #fileSave);
  194.   add(actions, PW_FILE_SAVEAS, #fileSaveAs);
  195.   add(actions, PW_FILE_PRINT, #print);
  196.   add(actions, PW_FILE_PRINT_GRAPH, #printGraphs);
  197.   add(actions, PW_RUN, #run);
  198.   add(actions, PW_FILE_QUIT, #close);
  199.   add(actions, PW_CLIP, #clipChart);
  200.   add(actions, PW_ABOUT_ACTOR, #aboutActor);
  201.   add(actions, PW_DEL_ACTIVITY, #deleteActivity);
  202.   add(actions, PW_DEL_RESOURCE, #deleteResource);
  203.   add(actions, PW_NEW_MSTONE, #newMilestone);
  204.   add(actions, PW_NEW_TASK, #newTask);
  205.   add(actions, PW_NEW_PERT, #newPERTTask);
  206.   add(actions, PW_DISPLAY, #displaySettings);
  207.   add(actions, PW_COLOR, #toggleColor);
  208.   add(actions, PW_AUTOCALC, #autoCalc);
  209.   add(actions, PW_CALC, #recalc);
  210.   add(actions, PW_SHOWROOM, #showRoom);
  211.   add(actions, PW_ZOOM, #zoom);
  212.   add(actions, PW_VIEW_SUMMARY, #viewSummary);
  213.   add(actions, PW_VIEW_ACTIVITIES, #showActivities);
  214.   add(actions, PW_VIEW_GANTT, #gantt);
  215.   add(actions, PW_VIEW_RESOURCES, #showResources);
  216.   add(actions, PW_VIEW_RESOURCE, #editResource);
  217.  
  218.     /* keyboard accelerator commands */
  219.     
  220.   add(actions, PW_HELP, #help);
  221.   add(actions, EDIT_HOME, #home);
  222.   add(actions, PW_COMMAND_MODE, #commandMode);
  223. }!!
  224.  
  225. /* Convert window coordinates to relative display coordinates. */
  226. Def windowToDisplay(self, wPoint)
  227. {
  228.   ^point((x(wPoint) - boxHSpace) / activWidth  + hScrollPos,
  229.          (y(wPoint) - boxHeight) / (boxHeight*2) + vScrollPos);
  230. }!!
  231.  
  232. /* Convert relative display entries to window coordinates. 
  233.    Uses dot notation for speed. */
  234. Def displayToWindow(self, dPoint)
  235. {
  236.    ^point(boxHSpace + (dPoint.x - hScrollPos) * activWidth,
  237.           boxHeight + (dPoint.y - vScrollPos) * boxHeight*2);          
  238. }!!
  239.  
  240. /* The name of application, used for captions. */
  241. Def  appName(self)
  242.   ^loadString(PW_APPNAME);
  243. }!!
  244.  
  245. /* Check if there is a file error and display an error box. 
  246.    Return the error number, 0 for no error. */
  247. Def checkError(self, aFile | errNo)
  248. {
  249.    errNo := getError(aFile);
  250.    if errNo <> 0
  251.      beep();
  252.      errorBox(loadString(PW_FILEERR1),
  253.               loadString(PW_FILEERR2) + asString(aFile) +
  254.               loadString(PW_FILEERR3) + asString(errNo) +
  255.               loadString(50+errNo));
  256.    endif;
  257.    ^errNo;
  258. }!!
  259.  
  260. /* Returns true if the node is visible in the window.
  261.    Used to speed up redrawing. Uses dot notation for speed. */
  262. Def visible(self, aNode)
  263.   ^between(aNode.x, hScrollPos, maxVisCol + hScrollPos)
  264.      cand between(aNode.y, vScrollPos, maxVisRow + vScrollPos);
  265. }!!
  266.  
  267. /* Set up the cursor for use even if there is no mouse. */
  268. Def gotFocus(self, prevHwnd)
  269.   Call ShowCursor(1);
  270. }!!
  271.  
  272. /* Return to normal use of cursor.  */
  273. Def losingFocus(self, hWndNew)
  274.   Call ShowCursor(0);
  275. } !!
  276.  
  277. /* Check if the project has been saved. */
  278. Def shouldClose(self)
  279.   ^checkClean(self)
  280. }!!
  281.  
  282. /* Make sure the window knows that the project has changed. */
  283. Def dirty(self)
  284. {
  285.   invalidate(self);
  286.   dirty := true;
  287.   if gw
  288.     invalidate(gw);
  289.   endif;
  290. }!!
  291.  
  292. /* Returns boolean value true if the project has
  293.    not changed since last save.  If it is dirty,
  294.    the user is prompted for confirmation.  */
  295. Def checkClean(self)
  296. {
  297.   ^ not(dirty) cor 
  298.      yesNoBox(loadString(PW_WARNING),
  299.               loadString(PW_DISCARD)) == IDYES;
  300. }!!
  301.  
  302. /* Get the offset of the botMethod. */
  303. Def getBotMethod(self)
  304. {
  305.   ^botMethod;
  306. }!!
  307.  
  308. /* Get the offset of the topMethod. */
  309. Def getTopMethod(self)
  310. {
  311.   ^topMethod;
  312. }!!
  313.  
  314. /* Resize the window.  Adjust visible rows and cols. */
  315. Def reSize(self, wp, lp)
  316.   maxVisRow := bottom(clientRect(self)) / (boxHeight*2);
  317.   maxVisCol := right(clientRect(self)) / activWidth;
  318. }!!
  319.  
  320. /* Respond to MS-Windows messages to paint the window. 
  321.    Show the project as a network chart.
  322.    Draw each visible node in its proper position. 
  323.    Display the name and any other info required.
  324.    Then draw the lines to connect the outputs.
  325.    
  326.    The displayToWindow message converts a node's
  327.    logical display position to windows coordinates.
  328.    
  329.    This could be further speeded up by repainting 
  330.    only the invalid rectangle.
  331. */
  332. Def paint(self, hDC |wPoint, x, y)
  333. {
  334.   do(nodes(project), 
  335.    {using(aNode)
  336.    
  337.    wPoint := displayToWindow(self, pos(aNode));
  338.    x := x(wPoint);    /* horiz windows posn */
  339.    y := y(wPoint);    /* vert windows posn */
  340.     
  341.    if visible(self, aNode)
  342.      draw(aNode, self, x, y, hDC);  /* node knows how to draw */ 
  343.      drawTextInfo(self, aNode, x, y, hDC);
  344.    endIf;
  345.    /* always draw connections since they may be visible */
  346.    drawConnections(self, aNode, x, y, getOutputs(aNode), hDC);
  347.   }); 
  348. }!!
  349.  
  350. /* Draw lines connecting the nodes in the window. 
  351.    Uses early binding, dot notation and direct
  352.    Windows calls for speed. */
  353. Def drawConnections(self, aNode, x, y, connectedNodes, hDC | wPoint)
  354. {
  355.      do(connectedNodes,
  356.        {using(output)  
  357.         Call MoveTo(hDC,  x + boxWidth, y + boxHeight/2);
  358.         wPoint := displayToWindow(self:ProjWindow, pos(output));
  359.         Call LineTo(hDC, wPoint.x, wPoint.y + boxHeight/2);
  360.  
  361.         if critical(aNode:Activity) cand critical(output:Activity)  
  362.           Call MoveTo(hDC,  x + boxWidth, y + boxHeight/2+1);
  363.           Call LineTo(hDC, wPoint.x, wPoint.y + boxHeight/2+1);
  364.         endif;       
  365.      });   
  366. }!!
  367.  
  368. /* Draw text info in the window.  If the small view is
  369.    being used, show less information.
  370.    Uses early binding and dot notation for speed. */
  371. Def drawTextInfo(self, aNode, x, y, hDC | ts, str, strSize, offsetY, offsetX)
  372. {
  373.  ts := textSize(self, hDC);
  374.  offsetY := (boxHeight - ts.y) / 2;
  375.  strSize := boxWidth / ts.x;
  376.  if view == #small
  377.    offsetX := 2;   /* to make milestones look ok */
  378.  else
  379.    offsetX := 0;
  380.  endif;
  381.  
  382.  str := subString(aNode.name, 0, strSize-1);
  383.  Call SetTextColor(hDC, SlackColor);
  384.  Call TextOut(hDC, x + offsetX + 2, y + offsetY, str, size(str));     
  385.  
  386.  if critical(aNode)
  387.    Call SetTextColor(hDC, CritColor);
  388.  endif;
  389.  
  390.  if topMethod     /* display above box */
  391.    str := subString(asString(perform(aNode, methTable[topMethod])),0,strSize);
  392.    Call TextOut(hDC, x + 2, y - ts.y, str, size(str));
  393.  endif;
  394.  
  395.  if view ~= #small
  396.  cand botMethod     /* display below box */
  397.      str :=  subString(asString(perform(aNode, methTable[botMethod])),0,strSize);
  398.      Call TextOut(hDC, x + 2, y + boxHeight, str, size(str));
  399.  endif;
  400. }!!
  401.  
  402. /* Draw a task in the window. 
  403.    Uses early binding and direct Windows call for speed. */
  404. Def drawTask(self, aNode, x, y, hDC)
  405. {
  406.   Call Rectangle(hDC, x, y, x + boxWidth, y + boxHeight); 
  407.   if critical(aNode:Activity)
  408.     Call Rectangle(hDC, x+1, y+1, x + boxWidth-1, y + boxHeight-1);
  409.   endif;
  410. }!!
  411.  
  412. /* Draw a milestone in the window. 
  413.    Uses early binding and direct Windows call for speed. */
  414. Def drawMilestone(self, aNode, x, y, hDC)
  415. {
  416.   Call RoundRect(hDC, x, y, x + boxWidth, y + boxHeight, 20,20);
  417.   if critical(aNode:Activity)
  418.     Call RoundRect(hDC, x+1, y+1, x + boxWidth-1, y + boxHeight-1, 17,17);
  419.   endif;     
  420. }!!
  421.  
  422. /* Handle menu events, accelerator keys.
  423.    Lookup the ID in the actions table, if found
  424.    perform it.  */
  425. Def command(self, wp, lp)
  426. {
  427.   if actions[wp]
  428.     perform(self, actions[wp]);
  429.   else  /* these keys might be accelerators */
  430.     if wp == VK_UP  cor wp == VK_DOWN cor
  431.        wp == VK_RIGHT cor wp == VK_LEFT
  432.       WM_KEYDOWN(self, wp, lp);
  433.     else
  434.       beep();  /* internal error! */
  435.       errorBox(loadString(PW_ERROR1),
  436.         loadString(PW_ERROR2) + asString(wp));
  437.     endif;
  438.   endif;
  439. }!!
  440.  
  441. /* Go into "command mode" in response to a slash key accelerator.
  442.    This simulates Lotus 1-2-3 style commands by sending an
  443.    ALT key sysCommand message. */
  444. Def commandMode(self)
  445.   WM_SYSCOMMAND(self, 0xF100, 0L);
  446. }!!
  447.  
  448. /* Get a filename from the user in responds to menu event.
  449.    If the file has changed, check with the user.
  450.    Send a fileOpen message to do the work. */
  451. /* Respond to menu choice to create a new project. */
  452. Def fileNew(self)
  453. {
  454.   if checkClean(self)
  455.     if gw
  456.       close(gw);
  457.     endif;
  458.     fileName := nil;
  459.     dirty := nil;  
  460.     setProject(self, new(Project));
  461.     checkMenuItem(self, PW_AUTOCALC);
  462.     setAutoCalc(project, true);
  463.     setText(self, appName(self));   
  464.     editInfo(project);
  465.     invalidate(self);
  466.   endif;
  467. }!!
  468.  
  469. /* Prompt the user for the filename to open. */
  470. Def fileOpenAs(self | dlg, file, reader)
  471. {
  472.   if checkClean(self)
  473.     dlg := new(FileDialog, "*."+loadString(PW_EXTENSION));
  474.     if runModal(dlg, FILE_BOX, self) == IDOK
  475.       fileName := getFile(dlg);    
  476.       fileOpen(self, fileName);
  477.     endif;
  478.   endif;
  479. }!!
  480.  
  481. /* Open the file named fName and read a project from disk.
  482.    If a DOS error occurs (like file not found) then stop.
  483.    Uses the Language Extensions I object storage facility. 
  484.    This method copies the file into a stream so that it
  485.    can read faster.  Also, the old project, file and stream
  486.    are set to nil as soon as possible to free up memory. */
  487. Def fileOpen(self, fName | dlg, file, strm, reader)
  488. {
  489.   showWaitCurs();                       /* this takes a while */
  490.   if gw
  491.     close(gw);                          /* close old GanttWindow */
  492.   endif;      
  493.    
  494.   file := new(File);                    /* open the file etc. */
  495.   setName(file, fName);
  496.   open(file, 0);
  497.   if checkError(self, file) == 0        /* no DOS errors */
  498.     project := nil;                     /* free up memory */        
  499.   
  500.     strm := streamOver(copyFrom(file, 0, length(file))); 
  501.     close(file);
  502.     setText(self, appName(self)+": " + fName);  
  503.  
  504.     reader := new(StoredObjectReader);    
  505.     project := readFrom(reader, strm);  /* read the project */
  506.     strm := nil;                        /* free up memory */
  507.     
  508.     setAutoCalc(project, true);         /* other settings */
  509.     checkMenuItem(self, PW_AUTOCALC);
  510.     dirty := nil;
  511.     invalidate(self);                   /* redraw the window */
  512.   else
  513.     fileName := nil;                    /* due to DOS error */
  514.   endif;
  515.   showOldCurs();                        /* all done */
  516. }!!
  517.  
  518. /* Respond to menu choice to save the file.  If the file
  519.    isn't yet named, prompt the user for a name. */
  520. Def fileSave(self)
  521. {
  522.   if fileName
  523.     fileSaveIt(self, fileName);
  524.   else
  525.     fileSaveAs(self);
  526.   endif;
  527. }!!
  528.  
  529. /* Save the project to disk with a new name. */
  530. Def fileSaveAs(self | dlg)
  531. {
  532.   if not(fileName)
  533.      fileName := getName(project)+"."+loadString(PW_EXTENSION);
  534.   endif;
  535.      
  536.   dlg := new(InputDialog, loadString(PW_APPNAME),
  537.              loadString(PW_SAVEPROJ), fileName);
  538.   if runModal(dlg, INPUT_BOX, self) == IDOK         
  539.      fileName := getText(dlg);
  540.      fileSaveIt(self, fileName);
  541.   endif;
  542. }!!
  543.  
  544. /* Save the project to disk with the filename fName. 
  545.    If a DOS error occurs (like file not found) stop. 
  546.    Uses the Language Extensions I object storage facility. 
  547.    Note: this will not save any global variables!  */
  548. Def fileSaveIt(self, fName | file)
  549. {
  550.   showWaitCurs();                          /* this takes a while */
  551.   file := new(File);                       
  552.   setName(file, fName);
  553.   create(file);
  554.   if checkError(self, file) == 0           /* no DOS error */
  555.      setText(self, appName(self) + ": " + fileName);
  556.     storeOn(project, file, nil);           /* write to file */
  557.     close(file);
  558.     dirty := false;
  559.   else
  560.     fileName := nil;                       /* due to DOS error */
  561.   endif;
  562.   showOldCurs();
  563. }!!
  564.  
  565. /* Print a text summary of the project.
  566.    Uses the Printer class.  */
  567. Def print(self | prn)
  568. {
  569.   prn := new(Printer);
  570.   showWaitCurs();                              /* takes a while */
  571.   if start(prn, "Project", self)               /* start printing */
  572.      do(getInfoLines(project),
  573.        {using(line)
  574.         printLine(prn, line);
  575.      });
  576.      printLine(prn, " ");
  577.      printLine(prn, " ");
  578.      printLine(prn, loadString(PW_ACTIVT1)+":");
  579.      printLine(prn, loadString(PW_ACTIVT2));
  580.      printLine(prn, loadString(PW_ACTIVT3));
  581.      printLine(prn, "--------------------------------------------");
  582.      do(sortedActivities(project),
  583.        {using(aNode)
  584.         printLine(prn, getInfoLine(aNode));
  585.      });
  586.      
  587.      if size(resources(project)) > 0
  588.        printLine(prn, " ");
  589.        printLine(prn, " ");
  590.        printLine(prn, loadString(PW_REST1) + ":");
  591.        printLine(prn, loadString(PW_REST2));
  592.        printLine(prn, loadString(PW_REST3));
  593.        printLine(prn, "------------------------------------------");
  594.        do(resources(project),
  595.          {using(aRes)
  596.           printLine(prn, getInfoLine(aRes));
  597.        });
  598.      endif;
  599.      finish(prn);                             /* all done */
  600.      showOldCurs();
  601.   else
  602.     showOldCurs();
  603.     beep();
  604.     errorBox(loadString(PW_PRINTERR1),loadString(PW_PRINTERR2));
  605.   endif;
  606. }!!
  607.  
  608. /* Print graphics charts */
  609. Def printGraphs(self)
  610. {
  611.   printWindow(self, 1);
  612. }!!
  613.  
  614. /* Copy bitmap to clipboard */
  615. Def clipChart(self)
  616. {
  617.   clipWindow(self, 1);
  618. }
  619.  
  620. /* Create a new Milestone */
  621. Def newMilestone(self)
  622. {
  623.   newActivity(self, Milestone);
  624. }!!
  625.  
  626. /* Create a new Task */
  627. Def newTask(self)
  628. {
  629.   newActivity(self, Task);
  630. }!!
  631.  
  632. /* Create a new PERTTask */
  633. Def newPERTTask(self)
  634. {
  635.   newActivity(self, PERTTask);
  636. }!!
  637.  
  638. /* Create a new activity based on a menu choice. 
  639.    The nodeClass should be passed in as Task, Milestone etc.
  640.    Return the new activity or nil if canceled. */
  641. Def newActivity(self, nodeClass | activity)
  642. {  
  643.   activity := new(nodeClass);
  644.   setNetwork(activity, project);
  645.   if editInfo(activity) == IDOK   /* let user connect it */
  646.     if pos(activity) = 0@0        /* still not connected */
  647.       activity.y := 1;            /* safe location */
  648.       resetPosn(getNetwork(activity), activity, 0@0);
  649.     endif;
  650.     dirty(self);                  /* redraw etc. */
  651.     ^activity;
  652.   endif;
  653.   ^nil;
  654. }!!
  655.  
  656. /* Delete a resource in response to menu choice. 
  657.    Returns the deleted resource or nil if canceled. */
  658. Def deleteResource(self | dlg, name, res)
  659.   dlg := new(InputDialog, loadString(PW_DELRES1),
  660.       loadString(PW_DELRES2), "");
  661.   if runModal(dlg, INPUT_BOX, self) == IDOK
  662.     name := getText(dlg);
  663.     if res := checkResExists(project, name) 
  664.        delete(res, project);
  665.        dirty(self);
  666.        ^res;
  667.     endif;    
  668.   endif;
  669.   ^nil;
  670. }!!
  671.  
  672. /* Delete an activity in response to menu choice. 
  673.    Returns the deleted node or nil if canceled. */
  674. Def deleteActivity(self | dlg, name, node)
  675.   dlg := new(InputDialog, loadString(PW_DELACT1),
  676.       loadString(PW_DELACT2), "");
  677.   if runModal(dlg, INPUT_BOX, self) == IDOK
  678.     name := getText(dlg);
  679.     if node := checkNodeExists(project, name) 
  680.        delete(node);
  681.        dirty(self);
  682.        ^node;
  683.     endif;
  684.   endif;
  685.   ^nil
  686. }!!
  687.  
  688. /* Edit a particular resource in response to menu choice.
  689.    For now, ask the user which one. Return the resource
  690.    or nil if canceled. */
  691. Def editResource(self | dlg, res)
  692. {
  693.  dlg := new(InputDialog, loadString(PW_VIEWRES1), loadString(PW_VIEWRES2),"");
  694.  if runModal(dlg, INPUT_BOX, self) == IDOK
  695.    if res := checkResExists(project, getText(dlg))
  696.       editInfo(res);
  697.       dirty(self);
  698.       ^res;
  699.    endif;
  700.  endif;  
  701.  ^nil;
  702. }!!
  703.  
  704. /* If the user presses the home key, reset scroll posn. */
  705. Def home(self)
  706. {
  707.   hScrollPos := vScrollPos := 0;
  708.   Call SetScrollPos(hWnd, SB_HORZ, hScrollPos, 1);
  709.   Call SetScrollPos(hWnd, SB_VERT, vScrollPos, 1);
  710.   invalidate(self);
  711. }!!
  712.  
  713. /* If the right button is pressed, toggle the view
  714.    to allow zoom in and out */
  715. Def zoom(self)
  716. {
  717.    if view == #normal
  718.         setView(self, #small);
  719.    else
  720.         setView(self, #normal);
  721.    endif;
  722.    invalidate(self);
  723. }!!
  724.  
  725. /* Show the amount of memory available. */
  726. Def showRoom(self | temp)
  727.  temp := Call GlobalCompact(Call GlobalCompact(0)+16) / 1024;
  728.  
  729.  errorBox(loadString(PW_SHOWROOM1),
  730.    asString(temp) + loadString(PW_SHOWROOM2));
  731. }!!
  732.  
  733. /* Show all of the resources as a table. */
  734. Def showResources(self | str)
  735. {
  736.   str :=  loadString(PW_SHOWRES2) + CR_LF +
  737.          "-----------------------------------------------";
  738.   do(resources(project),
  739.     {using(res)  
  740.      str := str + CR_LF + getInfoLine(res);
  741.   });
  742.   
  743.   errorBox(loadString(PW_REST1), str);
  744. }!!
  745.  
  746. /* Respond to menu choice to recalculate. */
  747. Def recalc(self)
  748. {
  749.   showWaitCurs();
  750.   recalc(project);
  751.   invalidate(self);
  752.   if gw
  753.    invalidate(gw);
  754.   endif;
  755.   showOldCurs();
  756. }!!
  757.  
  758. /* The ganttWindow has closed.  */
  759. Def closeGantt(self)
  760. {
  761.   gw := nil;
  762.   enableMenuItem(self, PW_VIEW_GANTT);
  763. }!!
  764.  
  765. /* Respond to menu choice to set display options.  The user
  766.    can select information to be displayed above or below
  767.    the nodes in the window.  */
  768. Def displaySettings(self | dlg)
  769. {
  770.   dlg := new(PWSetDialog);
  771.   if runModal(dlg, SETTING_BOX, self) == IDOK
  772.      invalidate(self);
  773.   endif;
  774. }!!
  775.  
  776. /* Handle menu choice to create a Gantt chart. 
  777.    Create the window large enough to hold all of
  778.    the activities, plus some extra space. */
  779. Def gantt(self | height)
  780. {
  781.   if screenSize()=640@200
  782.     height := 10
  783.   else
  784.     height := 20;
  785.   endif;
  786.   gw := new(GanttWindow, self, nil, loadString(PW_GANTT),
  787.             rect(asInt(x(screenSize())/3), 
  788.               max(y(screenSize())-(size(project)+5)*height,10),
  789.               x(screenSize()), y(screenSize())));
  790.   setProject(gw, project);
  791.   show(gw,1);
  792.   grayMenuItem(self, PW_VIEW_GANTT);
  793. }!!
  794.  
  795. /* Display help information from resource file. */
  796. Def help(self | dlg)
  797. {
  798.   dlg := new(Dialog);
  799.   checkRunModal(dlg, PW_HELP_BOX, self);
  800. }!!
  801.  
  802. /* Display Actor information from resource file. */
  803. Def aboutActor(self | dlg)
  804. {
  805.   dlg := new(Dialog);
  806.   checkRunModal(dlg, PW_ABOUT_ACTOR_BOX, self);
  807. }!!
  808.  
  809. /* Handles menu choice to set autocalc. */
  810. Def autoCalc(self)
  811. {
  812.   if autoCalc(project)
  813.     unCheckMenuItem(self, PW_AUTOCALC);
  814.     setAutoCalc(project, false);
  815.   else
  816.     checkMenuItem(self, PW_AUTOCALC);
  817.     setAutoCalc(project, true);
  818.     recalc(self);
  819.   endif;
  820. }!!
  821.  
  822. /* Show all of the activities as a table. */
  823. Def showActivities(self | str)
  824. {
  825.   str := loadString(PW_SHOWACT2) + CR_LF +
  826.          "------------------------------------------";
  827.   do(sortedActivities(project),
  828.     {using(aNode)  
  829.      str := str + CR_LF + getInfoLine(aNode);
  830.   });
  831.   
  832.   errorBox(loadString(PW_ACTIVT1), str);
  833. }!!
  834.  
  835. /* Respond to menu choice to edit the project */
  836. Def viewSummary(self)
  837. {
  838.   editInfo(project);
  839. }!!
  840.  
  841. /* See if the user has double clicked on a box.
  842.    If so, bring up a dialog for editing. Return the
  843.    activity or nil if canceled. */
  844. Def WM_LBUTTONDBLCLK(self, wp, lp | dPoint, activity)
  845. {
  846.   dPoint := windowToDisplay(self, asPoint(lp));
  847.   activity := displayLookup(project, dPoint);
  848.   if activity                       /* logically true if found */
  849.     if editInfo(activity) == IDOK   /* user clicked on activity */
  850.       dirty(self);                  /* changes were made */
  851.       ^activity;
  852.     endif;
  853.   else                              /* false if nothing found */
  854.     beep();                         /* user clicked on dead space */
  855.   endif;
  856.   ^nil;
  857. }!!
  858.  
  859. /* If the right button is pressed, toggle the view
  860.    to allow zoom in and out */
  861. Def WM_RBUTTONDOWN(self, wp, lp)
  862. {
  863.   zoom(self);
  864. }!!
  865.  
  866. /* Trap keyboard events to simulate mouse. Cursor keys move
  867.    the cursor and scroll, return and F2 edit an activity.
  868.    Note anything defined as an accelerator will NOT cause
  869.    a WM_KEYDOWN message.  The keys W, X, A, D can also be 
  870.    used to move the cursor. */
  871. Def WM_KEYDOWN(self, wp, lp | pos, x, y, activity, max, dict)
  872.   pos := getCursorPos(self);    /* client coords */
  873.   x := x(pos);
  874.   y := y(pos);
  875.  
  876.   select
  877.     case wp == VK_UP or wp == asInt('W')
  878.       y := y - boxHeight*2;
  879.     endCase
  880.     case wp == VK_DOWN or wp == asInt('X')
  881.       y := y + boxHeight*2;
  882.     endCase
  883.     case wp == VK_LEFT or wp == asInt('A')
  884.       x := x - activWidth;
  885.     endCase
  886.     case wp == VK_RIGHT or wp == asInt('D')
  887.       x := x + activWidth;
  888.     endCase
  889.     case wp == VK_RETURN or wp == VK_F2  
  890.       WM_LBUTTONDBLCLK(self, 1, asLong(pos));
  891.     endCase    
  892.   endSelect;
  893.   
  894.  /* If the cursor is moving off screen, scroll. */
  895.   
  896.   select
  897.     case y < 0 
  898.       y := boxHeight;
  899.       WM_VSCROLL(self, SB_LINEUP, 1);
  900.     endCase
  901.     case y > max:=maxVisRow*boxHeight*2
  902.       y := max - boxHeight;
  903.       WM_VSCROLL(self, SB_LINEDOWN, 1);
  904.     endCase
  905.   endSelect;
  906.   
  907.   select
  908.     case x < 0 
  909.       x := boxHSpace;
  910.       WM_HSCROLL(self, SB_LINEUP, 1);
  911.     endCase
  912.     case x > max:=maxVisCol*activWidth
  913.       x := max - boxWidth;
  914.       WM_HSCROLL(self, SB_LINEDOWN, 1);
  915.     endCase
  916.   endSelect;
  917.  
  918.   setCursorPos(self, point(x,y));
  919. }!!
  920.  
  921. /* Trap scrolling.  Adjust as necesary.
  922.    The wp is the scroll code, the lp gives posn. */
  923. Def WM_HSCROLL(self, wp, lp | scroll)
  924.   select
  925.     case wp == SB_LINEUP 
  926.        scroll := -1;
  927.     endCase
  928.     case wp == SB_LINEDOWN 
  929.        scroll := 1;
  930.     endCase
  931.     case wp == SB_PAGEUP
  932.        scroll := negate(maxVisCol);
  933.     endCase;
  934.     case wp == SB_PAGEDOWN
  935.        scroll := maxVisCol;
  936.     endCase;
  937.     case wp == SB_THUMBPOSITION
  938.        hScrollPos := 0; scroll := low(lp);
  939.     endCase;
  940.     default
  941.        scroll := nil;
  942.   endSelect;
  943.  
  944.   if scroll 
  945.     hScrollPos := hScrollPos + scroll;    /* adjust */
  946.     hScrollPos := min(PW_MAX_COLS, max(0, hScrollPos));
  947.     Call SetScrollPos(hWnd, SB_HORZ, hScrollPos, 1);
  948.     invalidate(self);
  949.   endif;
  950. }!!
  951.  
  952. /* Trap scrolling.  Adjust as necesary.
  953.    The wp is the scroll code, the lp gives posn. */
  954. Def WM_VSCROLL(self, wp, lp | scroll)
  955.   select
  956.     case wp == SB_LINEUP 
  957.        scroll := -1;
  958.     endCase
  959.     case wp == SB_LINEDOWN 
  960.        scroll := 1;
  961.     endCase
  962.     case wp == SB_PAGEUP
  963.        scroll := negate(maxVisRow);
  964.     endCase;
  965.     case wp == SB_PAGEDOWN
  966.        scroll := maxVisRow;
  967.     endCase;
  968.     case wp == SB_THUMBPOSITION
  969.        vScrollPos := 0; scroll := low(lp);
  970.     endCase;
  971.   endSelect;
  972.  
  973.   if scroll
  974.     vScrollPos := vScrollPos + scroll;    /* adjust */
  975.     vScrollPos := min(PW_MAX_ROWS, max(0, vScrollPos));
  976.     Call SetScrollPos(hWnd, SB_VERT, vScrollPos, 1);
  977.     invalidate(self);
  978.   endif;
  979. }!!
  980.  
  981.  
  982. /* Begin dragging to allow the user to draw a line
  983.    that will connect two boxes.  Setup the anchorPt and
  984.    dragDC to allow dragging to do the drawing.
  985.    BW 02/05/89 */
  986. Def beginDrag(self, wp, aPt | dPoint, activity, dMode)
  987. {
  988.   dPoint := windowToDisplay(self, aPt);
  989.   activity := displayLookup(project, dPoint);
  990.   if activity   /* logically true if found */
  991.     anchorPt := aPt;
  992.     dragDC := getContext(self);
  993.     dMode := Call SetROP2(dragDC,7);
  994.     Call SelectObject(dragDC,Call GetStockObject(6));
  995.   endif;
  996. }!!
  997.  
  998. /* Do the drag and draw the feedback.
  999.    BW 02/05/89 */
  1000. Def drag(self, wp, aPt )
  1001. { if dragDC then
  1002.     if oldPt cand (oldPt <> aPt)
  1003.       then moveTo(anchorPt,dragDC);
  1004.         lineTo(oldPt,dragDC);
  1005.     endif;
  1006.     oldPt := aPt;
  1007.     moveTo(anchorPt,dragDC);
  1008.     lineTo(aPt,dragDC);
  1009.   endif;
  1010. }!!
  1011.  
  1012. /* Finish the drag connection of two tasks.
  1013.    Create a new task if necessary. */
  1014. Def endDrag(self, wp, aPt | dPoint1, dPoint2, activity1, activity2)
  1015. {
  1016.   if dragDC then
  1017.     dPoint2 := windowToDisplay(self, aPt);
  1018.     activity2 := displayLookup(project, dPoint2);
  1019.     if activity2  /* logically true if found */
  1020.       dPoint1 := windowToDisplay(self,anchorPt);
  1021.       activity1 := displayLookup(project, dPoint1);
  1022.       if activity1 <> activity2
  1023.         connect(project,getName(activity1),
  1024.           getName(activity2));
  1025.         invalidate(self);
  1026.       endif;
  1027.     else /* maybe the user wants a new node */
  1028.       if activity2 := newActivity(self,Task) then
  1029.         dPoint1 := windowToDisplay(self,anchorPt);
  1030.         activity1 := displayLookup(project, dPoint1);
  1031.         connect(project,getName(activity1),
  1032.           getName(activity2));
  1033.         invalidate(self);
  1034.       else
  1035.         moveTo(anchorPt,dragDC); /* erase last line*/
  1036.         lineTo(oldPt,dragDC);
  1037.       endif;
  1038.     endif;
  1039.     releaseContext(self,dragDC); /* done drawing */
  1040.     dragDC := nil;
  1041.     oldPt := nil;
  1042.   endif;
  1043. }!!
  1044.  
  1045.